#include "InSdkRingBuffer.h"
#include "InComPrint.h"

#define DEF_TAG             "RingBuf"

#define FREE_QUEUE_BUF_LIST \
    pthread_mutex_lock(&ring_buffer->mutex); \
    if (ring_buffer->head_buff != NULL) \
    { \
        free(ring_buffer->head_buff); \
        ring_buffer->head_buff = NULL; \
    } \
    if (ring_buffer->frame_info != NULL) \
    { \
        free(ring_buffer->frame_info); \
        ring_buffer->frame_info = NULL; \
    } \
    pthread_mutex_unlock(&ring_buffer->mutex);

/*
 * @Note:
 *	环形缓冲队列:
 *	1、读操作：queue对象的已写入个数write_num为0时，表示队列中没有数据；
 *	2、写操作：quue对象的已写入个数write_num等于最大数组最大长度时，表示队列数据已满不能再写；
 *	3、queue对象中的pos_r与pos_w均为当前可读、写的位置；
 *
 */
Com_s32 InSdk_RingBuf_Get_Frame(pStSdkRingBufInfo ring_buffer,pStSdkRingBufFrame frame)
{
    Com_s32 pos_r;
    Com_s32 ret = 0;
    StSdkRingBufFrame *pFrame;

    pthread_mutex_lock(&ring_buffer->mutex);

    if ((ring_buffer->pos_r == ring_buffer->pos_w) && (ring_buffer->pos_r == -1))
    {
        ret = -2;
        goto Exit_get_one_frame;
    }

    if (ring_buffer->write_num <= 0)
    {
        ret = -1;
        //printf ("push ring_buffer empty, no data ...\n");
    }
    else
    {
        // printf("--------> pos_r= %d, pos_w= %d ,len= %d!\n",ring_buffer->pos_r, ring_buffer->pos_w, pFrame->frame_len);
        pFrame = &ring_buffer->frame_info[ring_buffer->pos_r];
        frame->frame_len = pFrame->frame_len;
        frame->frame_type = pFrame->frame_type;
        memcpy(frame->frame_buf, pFrame->frame_buf, pFrame->frame_len);
        pos_r = (ring_buffer->pos_r + 1) % ring_buffer->num_elements;
        ring_buffer->pos_r = pos_r;
        ring_buffer->write_num--;
    }

Exit_get_one_frame:
    pthread_mutex_unlock(&ring_buffer->mutex);
    return ret;
}

void InSdk_RingBuf_Position_Offset(pStSdkRingBufInfo ring_buffer,pStSdkRingBufFrame pFrame)
{
    pFrame->frame_buf = ring_buffer->head_buff + ring_buffer->use_len;
    ring_buffer->use_len += pFrame->frame_len;

    if(ring_buffer->use_len > ring_buffer->malloc_size)
    {
        //PRT_WARN(DEF_TAG,"use len is run out of,reset use buffer,use len: %d\n",ring_buffer->use_len);
        ring_buffer->use_len = 0;
        pFrame = &ring_buffer->frame_info[ring_buffer->pos_w];
        pFrame->frame_buf = ring_buffer->head_buff + ring_buffer->use_len;
    }
}

Com_s32 InSdk_RingBuf_Push_AudioFrame(pStSdkRingBufInfo ring_buffer,pStSdkRingBufFrame frame)
{
    Com_s32 pos_w;
    Com_s32 ret = 0;
    pStSdkRingBufFrame pFrame;

    pthread_mutex_lock(&ring_buffer->mutex);

    if ((ring_buffer->pos_r == ring_buffer->pos_w) && (ring_buffer->pos_r == -1))
    {
        ret = -2;
        goto Exit_audio_push_frame;
    }

    if (ring_buffer->write_num >= ring_buffer->num_elements)
    {
        //队列满了之后，需要丢弃所有的帧；
        ring_buffer->pos_r = ring_buffer->pos_w = ring_buffer->write_num = 0;
        ret = -1;
        //printf ("audio push ring_buffer has been full ...\n");
    }
    else
    {
//        printf ("+++++++++> pos_r= %d, pos_w= %d,len= %d !\n",
//                ring_buffer->pos_r, ring_buffer->pos_w,frame->frame_len);
        pFrame = &ring_buffer->frame_info[ring_buffer->pos_w];
        pFrame->frame_len = frame->frame_len;
        pFrame->frame_type = frame->frame_type;

        InSdk_RingBuf_Position_Offset(ring_buffer,pFrame);

        if (frame->frame_buf != NULL)
        {
            memcpy(pFrame->frame_buf, frame->frame_buf, frame->frame_len);
        }
        pos_w = (ring_buffer->pos_w + 1) % ring_buffer->num_elements;
        ring_buffer->pos_w = pos_w;
        ring_buffer->write_num++;
    }

Exit_audio_push_frame:
    pthread_mutex_unlock(&ring_buffer->mutex);
    return ret;
}

Com_s32 InSdk_RingBuf_Push_VideoFrame(pStSdkRingBufInfo ring_buffer,pStSdkRingBufFrame frame)
{
    static Com_s8 is_need_key_frame = 1;
    Com_s32 pos_w;
    Com_s32 ret = 0;
    pStSdkRingBufFrame pFrame;

    pthread_mutex_lock(&ring_buffer->mutex);

    if ((ring_buffer->pos_r == ring_buffer->pos_w) && (ring_buffer->pos_r == -1))
    {
        ret = -2;
        goto Exit_video_push_frame;
    }

    if (is_need_key_frame == 1)
    {
        if(frame->frame_type != 1)
        {
            ret = -3;
            goto Exit_video_push_frame;
        }
    }

    is_need_key_frame = 0;

    if (ring_buffer->write_num >= ring_buffer->num_elements)
    {
        //队列满了之后，需要丢弃所有的帧，并请求关键帧；
        is_need_key_frame = 1;
        ring_buffer->pos_r = ring_buffer->pos_w = ring_buffer->write_num = 0;
        ret = -1;
        //printf ("video push ring_buffer has been full ...\n");
    }
    else
    {
        //printf ("+++++++++> pos_r= %d, pos_w= %d,len= %d!\n",
        //        ring_buffer->pos_r, ring_buffer->pos_w,frame->frame_len);
        pFrame = &ring_buffer->frame_info[ring_buffer->pos_w];
        pFrame->frame_len = frame->frame_len;
        pFrame->frame_type = frame->frame_type;

        InSdk_RingBuf_Position_Offset(ring_buffer,pFrame);

        if (frame->frame_buf != NULL)
        {
            memcpy(pFrame->frame_buf, frame->frame_buf, frame->frame_len);
        }
        pos_w = (ring_buffer->pos_w + 1) % ring_buffer->num_elements;
        ring_buffer->pos_w = pos_w;
        ring_buffer->write_num++;
    }

Exit_video_push_frame:
    pthread_mutex_unlock(&ring_buffer->mutex);
    return ret;
}

Com_s32 InSdk_RingBuf_Init(pStSdkRingBufInfo ring_buffer,Com_s32 num_elements,Com_s32 malloc_size)
{
    Com_s32 i;
    Com_s32 ret = -1;

    ring_buffer->frame_info = (pStSdkRingBufFrame)malloc(num_elements * sizeof(StSdkRingBufFrame));
    ring_buffer->head_buff = (Com_ps8)malloc(malloc_size);

    ring_buffer->use_len = 0;
    ring_buffer->malloc_size = malloc_size;

    if((ring_buffer->frame_info != NULL) && ((ring_buffer->head_buff != NULL)))
    {
        memset(ring_buffer->head_buff,0,malloc_size);
        memset(ring_buffer->frame_info,0,num_elements * sizeof(StSdkRingBufFrame));

        ring_buffer->num_elements = num_elements;
        ring_buffer->pos_w = ring_buffer->pos_r = ring_buffer->write_num = 0;

        StSdkRingBufFrame *frame;
        for (i = 0; i < num_elements; i++)
        {
            frame = &ring_buffer->frame_info[i];
            frame->frame_buf = ring_buffer->head_buff;
        }

        ret = 0;
    }
    else
    {
        printf ("error %s, malloc for ring buffer fail ...\n",__FUNCTION__);
    }

    return ret;
}

Com_s32 Ext_InSdk_RingBuf_Create_AV_Info(pStSdkRingBufInfoProducer producer)
{
    InSdk_RingBuf_Init(&producer->mic_ring_buffer, DEF_SDK_AV_AUDIO_BUF_NUM, DEF_SDK_AV_AUDIO_BUF_SIZE);
    InSdk_RingBuf_Init(&producer->spk_ring_buffer, DEF_SDK_AV_AUDIO_BUF_NUM, DEF_SDK_AV_AUDIO_BUF_SIZE);
    InSdk_RingBuf_Init(&producer->video_ring_buffer,DEF_SDK_AV_VIDEO_BUF_NUM, DEF_SDK_AV_VIDEO_BUF_SIZE);

    producer->get_one_frame_from_ring_buffer = InSdk_RingBuf_Get_Frame;
    producer->push_video_frame_to_ring_buffer = InSdk_RingBuf_Push_VideoFrame;
    producer->push_audio_frame_to_ring_buffer = InSdk_RingBuf_Push_AudioFrame;

    pthread_mutex_init(&producer->mic_ring_buffer.mutex, NULL);
    pthread_mutex_init(&producer->spk_ring_buffer.mutex, NULL);
    pthread_mutex_init(&producer->video_ring_buffer.mutex, NULL);

    return 0;
}

Com_s32 Ext_InSdk_RingBuf_Distroy_AV_Info(pStSdkRingBufInfoProducer producer)
{
    pStSdkRingBufInfo ring_buffer;

    ring_buffer = &producer->video_ring_buffer;
    FREE_QUEUE_BUF_LIST;

    ring_buffer = &producer->mic_ring_buffer;
    FREE_QUEUE_BUF_LIST;

    ring_buffer = &producer->spk_ring_buffer;
    FREE_QUEUE_BUF_LIST;

    return 0;
}
